﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CRMAdminDashboard.CrmSvc;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Web.Services.Protocols;

namespace CRMAdminDashboard
{
    /// <summary>
    /// Code behind FormManageViews
    /// </summary>
    public class HelperManageViews : HelperBase
    {

        #region Constants

        private const string RES_VIEWSFORM_CLONECONFIRM1 = "RES_VIEWSFORM_CLONECONFIRM1";
        private const string RES_VIEWSFORM_CLONECONFIRM2 = "RES_VIEWSFORM_CLONECONFIRM2";
        private const string RES_VIEWSFORM_CLONECONFIRM3 = "RES_VIEWSFORM_CLONECONFIRM3";
        private const string RES_VIEWSFORM_CLONECONFIRM_TITLE = "RES_VIEWSFORM_CLONECONFIRM_TITLE";
        private const string RES_VIEWSFORM_ACTIVATECONFIRM1 = "RES_VIEWSFORM_ACTIVATECONFIRM1";
        private const string RES_VIEWSFORM_ACTIVATECONFIRM2 = "RES_VIEWSFORM_ACTIVATECONFIRM2";
        private const string RES_VIEWSFORM_ACTIVATECONFIRM3 = "RES_VIEWSFORM_ACTIVATECONFIRM3";
        private const string RES_VIEWSFORM_ACTIVATECONFIRM4 = "RES_VIEWSFORM_ACTIVATECONFIRM4";
        private const string RES_VIEWSFORM_ACTIVATECONFIRM_TITLE = "RES_VIEWSFORM_ACTIVATECONFIRM_TITLE";
        private const string RES_VIEWSFORM_MACTIVATECONFIRM1 = "RES_VIEWSFORM_MACTIVATECONFIRM1";
        private const string RES_VIEWSFORM_MACTIVATECONFIRM2 = "RES_VIEWSFORM_MACTIVATECONFIRM2";
        private const string RES_VIEWSFORM_MACTIVATECONFIRM3 = "RES_VIEWSFORM_MACTIVATECONFIRM3";
        private const string RES_VIEWSFORM_MACTIVATECONFIRM4 = "RES_VIEWSFORM_MACTIVATECONFIRM4";
        private const string RES_VIEWSFORM_MACTIVATECONFIRM5 = "RES_VIEWSFORM_MACTIVATECONFIRM5";
        private const string RES_VIEWSFORM_MACTIVATECONFIRM_TITLE = "RES_VIEWSFORM_MACTIVATECONFIRM_TITLE";
        private const string RES_VIEWSFORM_DELETECONFIRM1 = "RES_VIEWSFORM_DELETECONFIRM1";
        private const string RES_VIEWSFORM_DELETECONFIRM2 = "RES_VIEWSFORM_DELETECONFIRM2";
        private const string RES_VIEWSFORM_DELETECONFIRM_TITLE = "RES_VIEWSFORM_DELETECONFIRM_TITLE";

        private const int ONEXIST_ASK = 0;
        private const int ONEXIST_SKIP = 1;
        private const int ONEXIST_OVERWRITE = 2;
        private const int ONEXIST_CREATENEW = 3;
        private const int ONEXIST_CREATE = 4;

        #endregion

        #region Fields

        /// <summary>
        /// The CRM Service handle
        /// </summary>
        private CachingCrmService _svcHandle;

        /// <summary>
        /// Relationship between roles
        /// </summary>
        private RoleUserHierarchy _rUHierarchy;

        #endregion

        #region Properties

        /// <summary>
        /// Views fetched from the DB. Cached.
        /// </summary>
        Dictionary<Guid, UserQuery> FetchedViews { get; set; }

        /// <summary>
        /// A combination of the selected query types. Note that in SelectedQueryTypes "MainApplicationView"
        /// is represented by 4096 instead than 0.
        /// </summary>
        public uint SelectedQueryTypes { get; set; }

        /// <summary>
        /// BuFilter is persisted in RoleUserHierarchy
        /// </summary>
        public Dictionary<Guid, BusinessUnit> BuFilter
        {
            get
            {
                return RUHierarchy.BuFilter;
            }
        }

        /// <summary>
        /// Relationship between roles
        /// </summary>
        public RoleUserHierarchy RUHierarchy
        {
            get
            {
                if (_rUHierarchy == null)
                {
                    _rUHierarchy = new RoleUserHierarchy(this._svcHandle);
                }
                return _rUHierarchy;
            }
        }

        /// <summary>
        /// Print format for ToString()
        /// </summary>
        public static int QueryPrintFormat { get; set; }

        #endregion

        #region Entry Points

        /// <summary>
        /// Standard ctor.
        /// </summary>
        public HelperManageViews(CachingCrmService svcHandle)
        {
            this._svcHandle = svcHandle;
        }

        /// <summary>
        /// Get all user and populate the list boxes
        /// </summary>
        public void GetUsers(ListBox lstFromUsers, ListBox lstToUsers)
        {
            lstFromUsers.SelectedIndex = -1;
            lstFromUsers.Items.Clear();
            lstToUsers.SelectedIndex = -1;
            lstToUsers.Items.Clear();
            this.RUHierarchy.Clear();
            this._svcHandle.InvalidateCache();

            try
            {
                // get the BUs
                FormSelectBUs dialog = new FormSelectBUs(this._svcHandle);
                dialog.BuFilter = this.RUHierarchy.BuFilter;
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    this.RUHierarchy.BuFilter = dialog.BuFilter;

                    foreach (SystemUser su in this.RUHierarchy.FilteredUsers.Values)
                    {
                        lstFromUsers.Items.Add(su);
                        lstToUsers.Items.Add(su);
                    }
                }
            }
            catch (Exception ex)
            {
                FormManageViews.WriteLog(true, ex);
            }
        }

        /// <summary>
        /// Get all user's view and populate the list box
        /// </summary>
        /// <param name="loadFromDb">if true: load the views from the database. if false: refilter the cached ones</param>
        public void GetViews(SystemUser fromUser, ListBox lstViews, bool loadFromDb)
        {
            lstViews.SelectedIndex = -1;
            lstViews.Items.Clear();

            // only fetch views if there are users selected
            if (fromUser != null)
            {
                try
                {
                    if (loadFromDb || this.FetchedViews == null)
                    {
                        this.FetchedViews = UserQuery.GetViewsByUser(this._svcHandle, fromUser, UserQuery.UserQueryColumnSet);
                    }
                    foreach (UserQuery uq in this.FetchedViews.Values)
                    {
                        if (SavedQueryType.IsQuerySelected(uq, this.SelectedQueryTypes))
                        {
                            lstViews.Items.Add(uq);
                        }
                    }
                }
                catch (SoapException ex)
                {
                    FormManageViews.WriteLog(true, ex);
                    if (ex.Detail.InnerText.Contains("nvalid user auth"))
                    {
                        FormManageViews.WriteLog(true, "The logged in user does not have enough privileges" +
                            " to perform the requested operation." + Environment.NewLine +
                            "Try adding it to the \"PrivUserGroup\" Active Directory group." + Environment.NewLine +
                            "Note that this operation is not valid in a CRM Online scenario.");
                    }
                }
                catch (Exception ex)
                {
                    FormManageViews.WriteLog(true, ex);
                }
            }
        }

        /// <summary>
        /// Show the serialized view
        /// </summary>
        /// <param name="showFetchOnly">if true: show only the FetchXML field (unescaped)</param>
        public void ShowView(IEnumerable<UserQuery> views, Guid userId, int showType)
        {
            try
            {
                if (views.Count<UserQuery>() > 1 && showType == 2)
                {
                    MessageBox.Show("Cannot show view properties when multiple views are selected. Please choose another visualization option or select only one view.", "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                // Need to read all views again with All Columns
                List<Object> list = new List<Object>();
                foreach (UserQuery uq in views)
                {
                    list.Add(uq.Id);
                }

                Dictionary<Guid, UserQuery> selViews = UserQuery.GetViewsByUser(_svcHandle, userId, list.ToArray(), new AllColumns());

                StringWriter writer = new StringWriter();
                FormShowText showText;
                if (showType == 0)
                {
                    List<SerializableUserQuery> serViews = new List<SerializableUserQuery>();
                    foreach (UserQuery uq in selViews.Values)
                    {
                        serViews.Add(new SerializableUserQuery(uq));
                    }

                    XmlSerializer serializer = new XmlSerializer(typeof(List<SerializableUserQuery>));
                    showText = new FormShowText(IndentXml(serializer, serViews), true);
                    showText.Text = "Show Views (XML)";
                }
                else if (showType == 1)
                {
                    writer.Write("<?xml version=\"1.0\" encoding=\"utf-8\"?><arrayofuserquery>");
                    foreach (UserQuery uq in selViews.Values)
                    {
                        writer.Write("<userquery><name>" + uq.Name + "</name>");
                        writer.Write(uq.InnerUserQuery.fetchxml);
                        writer.Write("</userquery>");
                    }
                    writer.Write("</arrayofuserquery>");
                    showText = new FormShowText(IndentXml(writer.ToString()), true);
                    showText.Text = "Show Views (Fetch)";
                }
                else
                {
                    UserQuery uq = selViews.Values.ElementAt(0);
                    StringBuilder sb = new StringBuilder();

                    sb.AppendLine(string.Format("         ID: {0}", uq.InnerUserQuery.userqueryid.Value));
                    sb.AppendLine(string.Format("         BU: {0}", uq.InnerUserQuery.owningbusinessunit.Value));
                    sb.AppendLine(string.Format("      Owner: {0}", uq.InnerUserQuery.ownerid.name));
                    sb.AppendLine(string.Format("       Name: {0}", uq.InnerUserQuery.name));
                    sb.AppendLine(string.Format("  Type Code: {0}", uq.InnerUserQuery.returnedtypecode));
                    sb.AppendLine(string.Format(" Query Type: {0}", uq.InnerUserQuery.querytype.Value));
                    sb.AppendLine(string.Format("      Fetch: {0}", uq.InnerUserQuery.fetchxml));
                    sb.AppendLine(string.Format("     Layout: {0}", uq.InnerUserQuery.layoutxml));
                    sb.AppendLine(string.Format(" Column Set: {0}", uq.InnerUserQuery.columnsetxml));
                    sb.AppendLine(string.Format("     Descr.: {0}", uq.InnerUserQuery.description));
                    sb.AppendLine(string.Format("      State: {0}", uq.InnerUserQuery.statecode.Value));
                    sb.AppendLine(string.Format("     Status: {0}", uq.InnerUserQuery.statuscode == null ? "" : uq.InnerUserQuery.statuscode.name));
                    sb.AppendLine(string.Format(" Created By: {0}", uq.InnerUserQuery.createdby.name));
                    sb.AppendLine(string.Format("Modified By: {0}", uq.InnerUserQuery.modifiedby.name));
                    sb.AppendLine(string.Format(" Created On: {0}", uq.InnerUserQuery.createdon.Value));
                    sb.AppendLine(string.Format("Modified On: {0}", uq.InnerUserQuery.modifiedon.Value));

                    showText = new FormShowText(sb.ToString(), false);
                    showText.Text = "Show View";
                }

                showText.ShowDialog();
                if (showText.FileName != null)
                {
                    FormManageViews.WriteLog(true, string.Format("File [{0}] saved successfully." + Environment.NewLine, showText.FileName));
                }
            }
            catch (Exception ex)
            {
                FormManageViews.WriteLog(true, ex);
            }
        }

        /// <summary>
        /// Clone the selected views for the selected users.
        /// </summary>
        public void CloneViews(SystemUser fromUser, IEnumerable<UserQuery> views, IEnumerable<SystemUser> toUsers, int onExistingMode)
        {
            try
            {
                foreach (SystemUser user in toUsers)
                {
                    if (user.Id.Equals(fromUser.Id))
                    {
                        MessageBox.Show(string.Format("User \"{0}\" cannot be both source and destination.",
                            fromUser.ToString()), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                }

                if (!OperationConfirm(fromUser, views, toUsers, onExistingMode,
                    RES_VIEWSFORM_CLONECONFIRM1,
                    RES_VIEWSFORM_CLONECONFIRM2,
                    RES_VIEWSFORM_CLONECONFIRM3,
                    RES_VIEWSFORM_CLONECONFIRM_TITLE))
                {
                    return;
                }

                // get the views with All Columns
                List<Object> list = new List<Object>();
                foreach (UserQuery uq in views)
                {
                    list.Add(uq.Id);
                }
                Dictionary<Guid, UserQuery> selViews = UserQuery.GetViewsByUser(_svcHandle, fromUser.Id, list.ToArray(), new AllColumns());

                foreach (SystemUser user in toUsers)
                {
                    foreach (UserQuery view in selViews.Values)
                    {
                        CloneView(view, user, onExistingMode);
                    }
                }
            }
            catch (Exception ex)
            {
                FormManageViews.WriteLog(true, ex);
            }
        }

        /// <summary>
        /// Compare views of one user against a set of other users.
        /// </summary>
        public void CompareUsers(SystemUser fromUser, IEnumerable<SystemUser> toUsers)
        {
            try
            {
                foreach (SystemUser user in toUsers)
                {
                    if (user.Id.Equals(fromUser.Id))
                    {
                        MessageBox.Show(string.Format("User \"{0}\" cannot be both source and destination.",
                            fromUser.ToString()), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                }

                Dictionary<Guid, UserQuery> fromUserViews = UserQuery.GetViewsByUser(_svcHandle, this.SelectedQueryTypes, fromUser, new AllColumns());
                Dictionary<SystemUser, Dictionary<Guid, UserQuery>> toUserViewList = new Dictionary<SystemUser, Dictionary<Guid, UserQuery>>();
                foreach (SystemUser user in toUsers)
                {
                    Dictionary<Guid, UserQuery> views = UserQuery.GetViewsByUser(_svcHandle, this.SelectedQueryTypes, user, new AllColumns());
                    toUserViewList.Add(user, views);
                }

                StringBuilder diff = new StringBuilder();
                foreach (SystemUser toUser in toUserViewList.Keys)
                {
                    CompareUserPair(fromUser, fromUserViews, toUser, toUserViewList[toUser], diff);
                }

                FormShowText showText = new FormShowText(diff.ToString(), false);
                showText.Text = "User Differences";

                showText.ShowDialog();
                if (showText.FileName != null)
                {
                    FormManageViews.WriteLog(true, string.Format("File [{0}] saved successfully." + Environment.NewLine, showText.FileName));
                }
            }
            catch (Exception ex)
            {
                FormManageViews.WriteLog(true, ex);
            }
        }

        /// <summary>
        /// Rename view.
        /// </summary>
        public bool RenameView(SystemUser user, UserQuery view)
        {
            try
            {
                FormInsertText form = new FormInsertText();
                form.Text = "Rename View";
                string oldName = view.Name;
                form.txtBox.Text = oldName;
                if (form.ShowDialog() == DialogResult.OK)
                {
                    string newName = form.txtBox.Text.Trim();
                    if (newName != oldName)
                    {
                        // impersonate
                        Guid originalCaller = _svcHandle.CrmAuthenticationTokenValue.CallerId;
                        try
                        {
                            userquery uq = new userquery();
                            uq.userqueryid = new Key();
                            uq.userqueryid.Value = view.Id;
                            uq.name = newName;

                            _svcHandle.CrmAuthenticationTokenValue.CallerId = user.Id;
                            _svcHandle.Update(uq);
                            _svcHandle.InvalidateCache();
                            FormManageViews.WriteLog(false, "View \"" + oldName + "\" renamed to \"" + newName + "\".");
                            return true;
                        }
                        finally
                        {
                            _svcHandle.CrmAuthenticationTokenValue.CallerId = originalCaller;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                FormManageViews.WriteLog(true, ex);
            }

            return false;
        }

        /// <summary>
        /// Activate/Deactivate views.
        /// </summary>
        public bool ActivateViews(SystemUser fromUser, IEnumerable<UserQuery> views, bool activate)
        {
            try
            {
                List<UserQuery> list = new List<UserQuery>();
                foreach (UserQuery uq in views)
                {
                    if (activate && uq.StateCode == UserQueryState.Inactive)
                    {
                        list.Add(uq);
                    }
                    else if (!activate && uq.StateCode == UserQueryState.Active)
                    {
                        list.Add(uq);
                    }
                }

                if (!OperationConfirm(fromUser, list, activate,
                    RES_VIEWSFORM_ACTIVATECONFIRM1,
                    RES_VIEWSFORM_ACTIVATECONFIRM2,
                    RES_VIEWSFORM_ACTIVATECONFIRM3,
                    RES_VIEWSFORM_ACTIVATECONFIRM4,
                    RES_VIEWSFORM_ACTIVATECONFIRM_TITLE))
                {
                    return false;
                }
                else if (DialogResult.Yes != MessageBox.Show("Are you sure you are sure?", "Confirm the confirm",
                        MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2))
                {
                    return false;
                }

                // impersonate
                Guid originalCaller = _svcHandle.CrmAuthenticationTokenValue.CallerId;
                try
                {
                    _svcHandle.CrmAuthenticationTokenValue.CallerId = fromUser.Id;
                    foreach (UserQuery uq in list)
                    {
                        SetStateUserQueryRequest request = new SetStateUserQueryRequest();
                        request.EntityId = uq.Id;
                        if (activate)
                        {
                            request.UserQueryState = UserQueryState.Active;
                            request.UserQueryStatus = 1;
                        }
                        else
                        {
                            request.UserQueryState = UserQueryState.Inactive;
                            request.UserQueryStatus = 2;
                        }

                        SetStateUserQueryResponse response = (SetStateUserQueryResponse)_svcHandle.Execute(request);

                        if (activate)
                        {
                            FormManageViews.WriteLog(false, "View \"" + uq.Name + "\" activated.");
                        }
                        else
                        {
                            FormManageViews.WriteLog(false, "View \"" + uq.Name + "\" deactivated.");
                        }
                    }

                    _svcHandle.InvalidateCache();
                    return true;
                }
                finally
                {
                    _svcHandle.CrmAuthenticationTokenValue.CallerId = originalCaller;
                }
            }
            catch (Exception ex)
            {
                FormManageViews.WriteLog(true, ex);
            }

            return false;
        }

        /// <summary>
        /// Activate/Deactivate views for selected users.
        /// </summary>
        public bool ActivateViewsForUsers(IEnumerable<UserQuery> views, IEnumerable<SystemUser> users, bool activate)
        {
            try
            {
                if (!OperationConfirm(views, users, activate,
                    RES_VIEWSFORM_MACTIVATECONFIRM1,
                    RES_VIEWSFORM_MACTIVATECONFIRM2,
                    RES_VIEWSFORM_MACTIVATECONFIRM3,
                    RES_VIEWSFORM_MACTIVATECONFIRM4,
                    RES_VIEWSFORM_MACTIVATECONFIRM5,
                    RES_VIEWSFORM_MACTIVATECONFIRM_TITLE))
                {
                    return false;
                }
                else if (DialogResult.Yes != MessageBox.Show("Are you sure you are sure?", "Confirm the confirm",
                        MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2))
                {
                    return false;
                }

                int retval = 0;
                foreach (SystemUser toUser in users)
                {
                    retval += ActivateViewsForUser(views, toUser, activate);
                }

                if (retval > 0)
                {
                    _svcHandle.InvalidateCache();
                }

                if (activate)
                {
                    FormManageViews.WriteLog(false, retval.ToString() + " views activated." + Environment.NewLine);
                }
                else
                {
                    FormManageViews.WriteLog(false, retval.ToString() + " views deactivated." + Environment.NewLine);
                }

                return retval != 0;
            }
            catch (Exception ex)
            {
                FormManageViews.WriteLog(true, ex);
            }

            return false;
        }

        /// <summary>
        /// Delete views.
        /// </summary>
        public bool DeleteViews(SystemUser fromUser, IEnumerable<UserQuery> views)
        {
            try
            {
                if (!OperationConfirm(fromUser, views,
                    RES_VIEWSFORM_DELETECONFIRM1,
                    RES_VIEWSFORM_DELETECONFIRM2,
                    RES_VIEWSFORM_DELETECONFIRM_TITLE))
                {
                    return false;
                }
                else if (DialogResult.Yes != MessageBox.Show("Are you sure you are sure?", "Confirm the confirm",
                        MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2))
                {
                    return false;
                }

                // impersonate
                Guid originalCaller = _svcHandle.CrmAuthenticationTokenValue.CallerId;
                try
                {
                    _svcHandle.CrmAuthenticationTokenValue.CallerId = fromUser.Id;
                    foreach (UserQuery uq in views)
                    {
                        _svcHandle.Delete(EntityName.userquery.ToString(), uq.Id);
                        FormManageViews.WriteLog(false, "View \"" + uq.Name + "\" deleted.");
                    }

                    _svcHandle.InvalidateCache();
                    return true;
                }
                finally
                {
                    _svcHandle.CrmAuthenticationTokenValue.CallerId = originalCaller;
                }
            }
            catch (Exception ex)
            {
                FormManageViews.WriteLog(true, ex);
            }

            return false;
        }

        #endregion

        #region Local Methods

        /// <summary>
        /// Confirm whether the operation can be carried out
        /// </summary>
        private bool OperationConfirm(SystemUser fromUser, IEnumerable<UserQuery> views,
            IEnumerable<SystemUser> toUsers, int onExistingMode,
            string res1, string res2, string res3, string res4)
        {
            string mode = null;
            switch (onExistingMode)
            {
                case ONEXIST_ASK:
                    mode = "choose what to do for each user";
                    break;
                case ONEXIST_SKIP:
                    mode = "skip (ignore) the cloning for that user";
                    break;
                case ONEXIST_OVERWRITE:
                    mode = "overwrite the view for that user";
                    break;
                case ONEXIST_CREATENEW:
                    mode = "create a new view with the same name";
                    break;
            }

            StringBuilder sb = new StringBuilder();
            sb.AppendLine(string.Format(Program.GetResString(res1), fromUser.FullName));
            sb.AppendLine();
            foreach (UserQuery sr in views)
            {
                sb.AppendLine("\t" + sr.Name);
            }
            sb.AppendLine();
            sb.AppendLine(Program.GetResString(res2));
            sb.AppendLine();
            foreach (SystemUser su in toUsers)
            {
                sb.AppendLine("\t" + su.FullName);
            }
            sb.AppendLine();
            sb.AppendLine(string.Format(Program.GetResString(res3), mode));

            if (MessageBox.Show(sb.ToString(), Program.GetResString(res4),
                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Confirm whether the operation can be carried out
        /// </summary>
        private bool OperationConfirm(IEnumerable<UserQuery> views, IEnumerable<SystemUser> users,
            bool activate,
            string res1, string res2, string res3, string res4, string res5, string res6)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(string.Format(Program.GetResString(res1),
                Program.GetResString(activate ? res2 : res3)));
            sb.AppendLine();
            foreach (UserQuery sr in views)
            {
                sb.AppendLine("\t" + sr.Name);
            }
            sb.AppendLine();
            sb.AppendLine(Program.GetResString(res4));
            sb.AppendLine();
            foreach (SystemUser su in users)
            {
                sb.AppendLine("\t" + su.FullName);
            }
            sb.AppendLine();
            sb.AppendLine(Program.GetResString(res5));

            if (MessageBox.Show(sb.ToString(), Program.GetResString(res6),
                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Confirm whether the operation can be carried out
        /// </summary>
        private bool OperationConfirm(SystemUser fromUser,
            IEnumerable<UserQuery> views,
            string res1, string res2, string res3)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(string.Format(Program.GetResString(res1), fromUser.FullName));
            sb.AppendLine();
            foreach (UserQuery sr in views)
            {
                sb.AppendLine("\t" + sr.Name);
            }
            sb.AppendLine();
            sb.AppendLine(Program.GetResString(res2));

            if (MessageBox.Show(sb.ToString(), Program.GetResString(res3),
                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Confirm whether the operation can be carried out
        /// </summary>
        private bool OperationConfirm(SystemUser fromUser, IEnumerable<UserQuery> views,
            bool activate,
            string res1, string res2, string res3, string res4, string res5)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(string.Format(Program.GetResString(res1),
                Program.GetResString(activate ? res2 : res3),
                fromUser.FullName));
            sb.AppendLine();
            foreach (UserQuery sr in views)
            {
                sb.AppendLine("\t" + sr.Name);
            }
            sb.AppendLine();
            sb.AppendLine(Program.GetResString(res4));

            if (MessageBox.Show(sb.ToString(), Program.GetResString(res5),
                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Clone the view for the user.
        /// </summary>
        private int CloneViewMethod(UserQuery view, SystemUser user, int onExistingMode, out UserQuery matchingView)
        {
            // check duplicates
            Dictionary<Guid, UserQuery> userViews = UserQuery.GetViewsByUser(_svcHandle, user, UserQuery.UserQueryColumnSet);
            matchingView = null;
            foreach (UserQuery uq in userViews.Values)
            {
                if (uq.Name == view.Name)
                {
                    matchingView = uq;
                    break;
                }
            }

            if (matchingView != null)
            {
                FormManageViews.WriteLog(false, "View \"" + view + "\" already exists for user \"" + user + "\": ");
                switch (onExistingMode)
                {
                    case ONEXIST_ASK:
                        FormDuplicateView form = new FormDuplicateView();
                        form.Message = string.Format(
                            "View \r\n\r\n\"{0}\"\r\n\r\nalready exists for user\r\n\r\n\"{1}\".\r\n\r\nPlease select one of the following options.",
                            view, user);
                        DialogResult result = form.ShowDialog();
                        switch (result)
                        {
                            case DialogResult.Ignore:
                                FormManageViews.WriteLog(false, "Skipped." + Environment.NewLine);
                                return ONEXIST_SKIP;

                            case DialogResult.Yes:
                                FormManageViews.WriteLog(false, "Overwrite." + Environment.NewLine);
                                return ONEXIST_OVERWRITE;

                            case DialogResult.Retry:
                                FormManageViews.WriteLog(false, "Create New." + Environment.NewLine);
                                return ONEXIST_CREATENEW;

                            case DialogResult.Cancel:
                                FormManageViews.WriteLog(false, "Operation aborted." + Environment.NewLine);
                                throw new ApplicationException("Operation Aborted");
                        }
                        break;

                    case ONEXIST_SKIP:
                        FormManageViews.WriteLog(false, "Skipped." + Environment.NewLine);
                        break;

                    case ONEXIST_OVERWRITE:
                        FormManageViews.WriteLog(false, "Overwrite." + Environment.NewLine);
                        break;

                    case ONEXIST_CREATENEW:
                        FormManageViews.WriteLog(false, "Create New." + Environment.NewLine);
                        break;
                }

                return onExistingMode;
            }
            else
            {
                return ONEXIST_CREATE;
            }
        }

        /// <summary>
        /// Clone the view for the user.
        /// </summary>
        private void CloneView(UserQuery view, SystemUser user, int onExistingMode)
        {
            UserQuery matchingView;
            int mode = CloneViewMethod(view, user, onExistingMode, out matchingView);

            Guid originalCaller = _svcHandle.CrmAuthenticationTokenValue.CallerId;
            try
            {
                _svcHandle.CrmAuthenticationTokenValue.CallerId = user.Id;
                userquery clonedView = view.CloneInner();
                switch (mode)
                {
                    case ONEXIST_CREATE:
                        clonedView.createdby = null;
                        clonedView.createdon = null;
                        clonedView.modifiedby = null;
                        clonedView.modifiedon = null;
                        clonedView.ownerid = null;
                        clonedView.owningbusinessunit = null;
                        clonedView.statecode = null;
                        clonedView.statuscode = null;
                        clonedView.userqueryid = null;

                        _svcHandle.Create(clonedView);
                        _svcHandle.InvalidateCache();
                        FormManageViews.WriteLog(false, "Created view \"" + view + "\" for user \"" + user + "\"." + Environment.NewLine);
                        break;

                    case ONEXIST_CREATENEW:
                        clonedView.createdby = null;
                        clonedView.createdon = null;
                        clonedView.modifiedby = null;
                        clonedView.modifiedon = null;
                        clonedView.ownerid = null;
                        clonedView.owningbusinessunit = null;
                        clonedView.statecode = null;
                        clonedView.statuscode = null;
                        clonedView.userqueryid = null;
                        clonedView.name = clonedView.name;

                        _svcHandle.Create(clonedView);
                        _svcHandle.InvalidateCache();
                        FormManageViews.WriteLog(false, "Created view \"" + view + "\" for user \"" + user + "\"." + Environment.NewLine);
                        break;

                    case ONEXIST_OVERWRITE:
                        clonedView.createdby = null;
                        clonedView.createdon = null;
                        clonedView.modifiedby = null;
                        clonedView.modifiedon = null;
                        clonedView.ownerid = null;
                        clonedView.owningbusinessunit = null;
                        clonedView.statecode = null;
                        clonedView.statuscode = null;
                        clonedView.userqueryid = matchingView.InnerUserQuery.userqueryid;

                        _svcHandle.Update(clonedView);
                        _svcHandle.InvalidateCache();
                        FormManageViews.WriteLog(false, "Updated view \"" + view + "\" for user \"" + user + "\"." + Environment.NewLine);
                        break;

                    default:
                        return;
                }
            }
            finally
            {
                _svcHandle.CrmAuthenticationTokenValue.CallerId = originalCaller;
            }
        }

        /// <summary>
        /// Compare the views of a pair of users
        /// </summary>
        private void CompareUserPair(SystemUser fromUser, Dictionary<Guid, UserQuery> fromUserViews,
            SystemUser toUser, Dictionary<Guid, UserQuery> toUserViews, StringBuilder diff)
        {
            string line = "* Comparing \"" + fromUser.ToStringShort() + "\" and \"" + toUser.ToStringShort() + "\":" + Environment.NewLine;
            FormManageViews.WriteLog(false, line);
            diff.Append(line);
            int origLen = diff.Length;

            Dictionary<string, UserQuery> fromUserViewsCopy = new Dictionary<string, UserQuery>();
            foreach (UserQuery uq in fromUserViews.Values)
            {
                string name = uq.Name;
                while (fromUserViewsCopy.ContainsKey(name))
                {
                    name = name + "*";
                }
                fromUserViewsCopy.Add(name, uq);
            }

            Dictionary<string, UserQuery> toUserViewsCopy = new Dictionary<string, UserQuery>();
            foreach (UserQuery uq in toUserViews.Values)
            {
                string name = uq.Name;
                while (toUserViewsCopy.ContainsKey(name))
                {
                    name = name + "*";
                }
                toUserViewsCopy.Add(name, uq);
            }

            foreach (string name in fromUserViewsCopy.Keys)
            {
                if (toUserViewsCopy.ContainsKey(name))
                {
                    UserQuery toView = toUserViewsCopy[name];
                    CompareViewPair(fromUserViewsCopy[name], toView, diff);
                    toUserViewsCopy.Remove(name);
                }
                else
                {
                    CompareViewPair(fromUserViewsCopy[name], null, diff);
                }
            }

            foreach (UserQuery toView in toUserViewsCopy.Values)
            {
                CompareViewPair(null, toView, diff);
            }

            if (diff.Length == origLen)
            {
                line = "   -- No differences." + Environment.NewLine;
                FormManageViews.WriteLog(false, line);
                diff.Append(line);
            }
        }

        /// <summary>
        /// Compare a pair of views
        /// </summary>
        private void CompareViewPair(UserQuery fromView, UserQuery toView, StringBuilder diff)
        {
            StringBuilder sb = new StringBuilder();
            if (fromView == null)
            {
                sb.Append("   -- View \"" + toView.Name + "\" exists only in right set." + Environment.NewLine);
            }
            else if (toView == null)
            {
                sb.Append("   -- View \"" + fromView.Name + "\" exists only in left set." + Environment.NewLine);
            }
            else
            {
                List<string> differences = new List<string>();
                if (!Object.Equals(fromView.InnerUserQuery.columnsetxml, toView.InnerUserQuery.columnsetxml))
                {
                    differences.Add("Column Set");
                }
                if (!Object.Equals(fromView.InnerUserQuery.description, toView.InnerUserQuery.description))
                {
                    differences.Add("Descritpion");
                }
                if (!Object.Equals(fromView.InnerUserQuery.fetchxml, toView.InnerUserQuery.fetchxml))
                {
                    differences.Add("Fetch");
                }
                if (!Object.Equals(fromView.InnerUserQuery.layoutxml, toView.InnerUserQuery.layoutxml))
                {
                    differences.Add("Layout");
                }
                if (!Object.Equals(fromView.InnerUserQuery.querytype.Value, toView.InnerUserQuery.querytype.Value))
                {
                    differences.Add("Query Type");
                }
                if (!Object.Equals(fromView.InnerUserQuery.returnedtypecode, toView.InnerUserQuery.returnedtypecode))
                {
                    differences.Add("Type Code");
                }
                if (!Object.Equals(fromView.InnerUserQuery.statecode.Value, toView.InnerUserQuery.statecode.Value))
                {
                    differences.Add("State");
                }

                /* we don't compare status, state is enough
                if (fromView.InnerUserQuery.statuscode == null && toView.InnerUserQuery.statuscode != null ||
                    fromView.InnerUserQuery.statuscode != null && toView.InnerUserQuery.statuscode == null ||
                    (fromView.InnerUserQuery.statuscode != null && toView.InnerUserQuery.statuscode != null &&
                    !Object.Equals(fromView.InnerUserQuery.statuscode.Value, toView.InnerUserQuery.statuscode.Value)))
                {
                    differences.Add("Status");
                }
                */

                if (differences.Count > 0)
                {
                    bool first = true;
                    sb.Append("   -- View \"");
                    sb.Append(fromView.Name);
                    sb.Append("\" different: ");
                    foreach (string str in differences)
                    {
                        if (first)
                        {
                            first = false;
                        }
                        else
                        {
                            sb.Append(", ");
                        }

                        sb.Append(str);
                    }
                    sb.Append(".");
                    sb.Append(Environment.NewLine);
                }
            }

            if (sb.Length > 0)
            {
                FormManageViews.WriteLog(false, sb.ToString());
                diff.Append(sb.ToString());
            }
        }

        /// <summary>
        /// Activate/Deactivate views for the user.
        /// </summary>
        private int ActivateViewsForUser(IEnumerable<UserQuery> views, SystemUser toUser, bool activate)
        {
            int retval = 0;

            FormManageViews.WriteLog(false, "User \"" + toUser.ToStringShort() + "\":" + Environment.NewLine);

            // impersonate
            Guid originalCaller = _svcHandle.CrmAuthenticationTokenValue.CallerId;
            try
            {
                _svcHandle.CrmAuthenticationTokenValue.CallerId = toUser.Id;
                Dictionary<Guid, UserQuery> userViews = UserQuery.GetViewsByUser(_svcHandle, toUser, UserQuery.UserQueryColumnSet);
                foreach (UserQuery uqTo in userViews.Values)
                {
                    foreach (UserQuery uqFrom in views)
                    {
                        if (uqFrom.Name == uqTo.Name && uqFrom.QueryType == uqTo.QueryType)
                        {
                            if (activate && uqTo.InnerUserQuery.statecode.Value == UserQueryState.Inactive ||
                                !activate && uqTo.InnerUserQuery.statecode.Value == UserQueryState.Active)
                            {
                                SetStateUserQueryRequest request = new SetStateUserQueryRequest();
                                request.EntityId = uqTo.Id;
                                if (activate)
                                {
                                    request.UserQueryState = UserQueryState.Active;
                                    request.UserQueryStatus = 1;
                                }
                                else
                                {
                                    request.UserQueryState = UserQueryState.Inactive;
                                    request.UserQueryStatus = 2;
                                }

                                SetStateUserQueryResponse response = (SetStateUserQueryResponse)_svcHandle.Execute(request);

                                FormManageViews.WriteLog(false, string.Format("  - View \"{0}\" {1}.{2}",
                                    uqTo.Name,
                                    activate ? "activated" : "deactivated",
                                    Environment.NewLine));

                                retval++;
                            }
                            else
                            {
                                FormManageViews.WriteLog(false, string.Format("  - View \"{0}\" already {1}.{2}",
                                    uqTo.Name,
                                    activate ? "active" : "inactive",
                                    Environment.NewLine));
                            }
                        }
                    }
                }
            }
            finally
            {
                _svcHandle.CrmAuthenticationTokenValue.CallerId = originalCaller;
            }

            return retval;
        }

        #endregion

    }
}